#include "fast_vector.h"
#include <stdexcept>
#include <exception>
#include <algorithm>


fast_vector::fast_vector() : size_(0), capacity_(1)
{
}

fast_vector::fast_vector(const fast_vector &a) : digits_()
{
   *this = a;
}

fast_vector::~fast_vector()
{
   if (capacity_ > 1)
      delete[] digits_.digits_;
}

fast_vector& fast_vector::operator =(const fast_vector& a)
{
   if (capacity_ > 1)
   {
      delete[] digits_.digits_;
      capacity_ = 1;
   }
   if (a.capacity_ == 1)
   {
      size_ = a.size_;
      capacity_ = 1;
      digits_.digit_ = a.digits_.digit_;
   }
   else
   {
      capacity_ = a.capacity_;
      size_ = a.size_;
      digits_.digits_ = new int[capacity_];
      for (size_t i = 0; i < size_; i++)
         digits_.digits_[i] = a.digits_.digits_[i];
   }
   return *this;
}


const int fast_vector::operator [](size_t index) const
{
   if (capacity_ == 1)
      return digits_.digit_;
   else
      return digits_.digits_[index];
}

int& fast_vector::operator [](size_t index)
{
   if (capacity_ == 1)
      return digits_.digit_;
   else
      return digits_.digits_[index];
}

void fast_vector::push_back(int x)
{
   if (size_ == 0 && capacity_ == 1)
   {
      digits_.digit_ = x;
      size_ = 1;
   }
   else
   {
      ensure_increase_capacity(size_ + 1);
      digits_.digits_[size_++] = x;
   }
}

void fast_vector::resize(size_t size)
{
   int * tmp = new int[size * 2];
   if (capacity_ == 1)
   {
      tmp[0] = digits_.digit_;
   }
   else
   {
      for (size_t i = 0; i < std::min(size, size_); i++)
         tmp[i] = digits_.digits_[i];
      delete[] digits_.digits_;
   }
   capacity_ = size * 2;
   for (size_t i = std::min(size, size_), max = std::max(size, size_); i < max; i++)
         tmp[i] = 0;
   size_ = size;
   digits_.digits_ = tmp;
}

int fast_vector::back()
{
   if (capacity_ == 1)
      return digits_.digit_;
   else
      return digits_.digits_[size_ - 1];
}

void fast_vector::reverse()
{
   if (capacity_ == 1)
      return;
   for (size_t i = 0; i < size_ / 2; i++)
      std::swap(digits_.digits_[i], digits_.digits_[size_ - i - 1]);
}

void fast_vector::erase(size_t start, size_t end)
{
   if (capacity_ == 1) 
   {
      clear();
      return;
   }
   int * tmp = new int[capacity_];
   for (size_t i = 0; i < start; i++)
      tmp[i] = digits_.digits_[i];
   for (size_t i = end; i < size_; i++)
   {
      tmp[start + i - end] = digits_.digits_[i];
   }
   size_ = size_ - (end - start);
   delete[] digits_.digits_;
   digits_.digits_ = tmp;
   ensure_decrease_capacity();
}

void fast_vector::clear()
{
   if (capacity_ > 1)
      delete[] digits_.digits_;
   size_ = 0;
   capacity_ = 1;
}

void fast_vector::ensure_decrease_capacity()
{
   if (size_ == 1)
   {
      int tmp = digits_.digits_[0];
      delete[] digits_.digits_;
      digits_.digit_ = tmp;
      capacity_ = 1;
      return;
   }
   if (size_ < capacity_ / 4)
   {
      capacity_ /= 2;
      int *tmp = new int[capacity_];
      for (size_t i = 0; i < size_; i++)
         tmp[i] = digits_.digits_[i];
      delete[] digits_.digits_;
      digits_.digits_ = tmp;
      return;
   }
}

void fast_vector::pop_back()
{
   --size_;
   ensure_decrease_capacity();
}

void fast_vector::ensure_increase_capacity(size_t size)
{
   if (size == 2 && capacity_ == 1)
   {
      int tmp = digits_.digit_;
      capacity_ = 4;
      digits_.digits_ = new int[capacity_];
      digits_.digits_[0] = tmp;
      return;
   }
   if (size >= capacity_)
   {
      capacity_ *= 2;
      int* tmp = new int[capacity_];
      for (size_t i = 0; i < size - 1; i++)
      {
         tmp[i] = digits_.digits_[i];
      }
      delete[] digits_.digits_;
      digits_.digits_ = tmp;
      return;
   }
}

void fast_vector::swap(fast_vector& a)
{
   std::swap(size_, a.size_);
   std::swap(capacity_, a.capacity_);
   std::swap(digits_, a.digits_);
}

size_t fast_vector::size() const
{
   return size_;
}